34. 在排序数组中查找元素的第一个和最后一个位置

34. 在排序数组中查找元素的第一个和最后一个位置

题目链接
代码随想录

分析

非递减顺序的意思是升序但是可能存在重复元素,O(logn),可以尝试使用二分法。
思路是用一个二分法找左边界,再写一个二分法找右边界,重点是如何通过二分法查找单个边界,
其实方式很简单,以查找右边界为例,还是通过二分法来查找,获取区间的中间元素的时候,如果中间元素大于目标值,就更新右区间,其余所有情况都更新左区间,这里跟经典的二分查找的区别是,经典的二分法写法是遇到目标值就跳出循环,但是这里是查找右边界,因此遇到目标元素依然更新左区间,继续收缩区间,同时记录一下当前 mid 为右边界值,这样的话,因为没有遇到某个值跳出循环的条件(老的二分法就是这样的),因此最终一定会扫描到右边界所在的值,最终跳出循环,上一个循环记录的边界值,就是最终的边界。
有的时候会想会不会跳过了最终边界,答案是不会,例如 5 5 5 8 10 12 14 15,假设当前区间是 [0,7] 目标是是 5 ,中间索引是 3,值是 8 ,中间索引的值小于目标值,更新右区间为 3-1,也就是 2,因此这样最终还是会找到右边界。
为什么不会,究其原因,主要因为数列是有序的,而且在每一次循环中,我们都在不断更新区间的左右边界,因此,只要我们对左右边界的定义不变,更新左右边界时的操作不出问题,那么在最终跳出循环的时候,我们就能按照我们设定好的方式,遍历完序列中所有的值,二分法的实际效果就是,即使只挑选几个值(每次区间的 mid 值),也能保证不遗漏。二分查找的本质,就是有序数列的一种快速遍历方式
左边界同理。

常规的二分法有三个变量,查询区间 [start,end] 和 区间中间索引值 mid,但是查找边界的二分法有第四个变量,边界 border。 而且常规的二分法以 mid 为最终值,但是查找边界的时候,border 值才是最终返回的值,二分法只是为了快速遍历。为什么二分法能快速遍历,因为数组有序。

public int[] searchRange(int[] nums, int target) {
    int leftBorder = binarySearchFromLeft(nums,target);
    int rightBorder = binarySearchFromRight(nums,target);
    return new int[]{leftBorder,rightBorder};
}

public int binarySearchFromRight(int[] nums,int target){
    int start=0, end = nums.length-1;
    int rightBorder = -1;
    while(start<=end){
        int mid = start+(end-start)/2;
        if (nums[mid]>target){
            // 从右侧确定右边界
            end = mid-1;
        } else {
            start = mid+1;
            if(nums[mid]==target){
                rightBorder = mid;
            }
        }
    }
    return rightBorder;
}

public int binarySearchFromLeft(int[] nums,int target){
    int start=0, end = nums.length-1;
    int leftBorder = -1;
    while(start<=end){
        int mid = start+(end-start)/2;
        if (nums[mid]<target){
            // 从左侧确定左边界
            start = mid+1;
        } else {
            end = mid-1;
            if(nums[mid]==target){
                leftBorder = mid;
            }
        }
    }
    return leftBorder;
}

解题

通过这个题,我们对二分法的的使用应该有一个更深层次的理解,二分法本质上是一种从有序数组两侧快速往中间逼近的方法,可以有效加快逼近的速度,而且不会遗漏元素。
而且这个题也让我们明白,只要是有序数组,不管有没有重复元素,都可以用二分法

相关题

704. 二分查找
35. 搜索插入位置
69. x 的平方根